package com.sunda.spmsoversea.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmsoversea.dto.*;
import com.sunda.spmsoversea.entity.*;
import com.sunda.spmsoversea.mapper.OverseaWhsOutMapper;
import com.sunda.spmsoversea.service.*;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

import static com.sunda.spmsoversea.constant.CommonConstant.*;
import static com.sunda.spmsoversea.constant.SapConstant.SAP_SUCCESS;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.*;
import static com.sunda.spmsoversea.enums.OverseaRequisitionEnum.REQUISITION_APPROVED;
import static com.sunda.spmsoversea.enums.OverseaRequisitionEnum.REQUISITION_DONE;
import static com.sunda.spmsoversea.enums.OverseaWhsOutEnum.*;

/**
 * <p>
 * 海外出库任务表 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-09-22
 */
@Service
@Slf4j
public class OverseaWhsOutServiceImpl extends ServiceImpl<OverseaWhsOutMapper, OverseaWhsOut> implements IOverseaWhsOutService {

    @Autowired
    IOverseaRequisitionService iOverseaRequisitionService;

    @Autowired
    IOverseaRequisitionDtlService iOverseaRequisitionDtlService;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IOverseaWhsOutDtlService iOverseaWhsOutDtlService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IFormatDataToSapService iFormatDataToSapService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    /** 更新领用申请每一行实际移动类型，然后根据类型的不同拆分出库任务； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult generateOverseaWhsOut(OverseaWhsOutGenerateDTO overseaWhsOutGenerateDTO, String userId) {
        ResponseResult checkResult = checkGenerateOverseaWhsOut(overseaWhsOutGenerateDTO);
        if (checkResult.getCode() != SUCCESS){
            return checkResult;
        }
        try {
            String uuidRequisition = overseaWhsOutGenerateDTO.getUuidRequisition();

            QueryWrapper<OverseaRequisition> overseaRequisitionQueryWrapper = new QueryWrapper<OverseaRequisition>().eq("UUID_REQUISITION", uuidRequisition);
            OverseaRequisition oRequisition = new OverseaRequisition();
            oRequisition.setCostCenter(overseaWhsOutGenerateDTO.getCostCenter());
            oRequisition.setCostCenterName(overseaWhsOutGenerateDTO.getCostCenterName());
            iOverseaRequisitionService.update(oRequisition, overseaRequisitionQueryWrapper);

            List<OverseaRequisitionDtlDTO> overseaRequisitionDtlDTOList = overseaWhsOutGenerateDTO.getRequisitionDtlDTOList();
            for (OverseaRequisitionDtlDTO dto : overseaRequisitionDtlDTOList){
                String actualMovementType = dto.getActualMovementType();
                Integer item = dto.getItem();
                QueryWrapper<OverseaRequisitionDtl> queryWrapper = new QueryWrapper<OverseaRequisitionDtl>()
                        .eq("UUID_REQUISITION", uuidRequisition).eq("ITEM", item);
                OverseaRequisitionDtl overseaRequisitionDtl = new OverseaRequisitionDtl();
                overseaRequisitionDtl.setActualMovementType(actualMovementType);
                iOverseaRequisitionDtlService.update(overseaRequisitionDtl, queryWrapper);
            }

            String createDate = overseaWhsOutGenerateDTO.getCreateDate();
            OverseaRequisition overseaRequisition = iOverseaRequisitionService.getOverseaRequisition(uuidRequisition);
            String relateDocument = overseaRequisition.getSpmsId();
            List<OverseaRequisitionDtl> overseaRequisitionDtlList = iOverseaRequisitionDtlService.getRequisitionDtls(uuidRequisition);

            Set<String> set = new HashSet<>();
            for (OverseaRequisitionDtl overseaRequisitionDtl : overseaRequisitionDtlList){
                double actualBasicUnit = overseaRequisitionDtl.getActualQtyBasicUnit();
                if (actualBasicUnit > 0){
                    set.add(overseaRequisitionDtl.getActualMovementType());
                }
            }
            for (String movementType : set){
                String uuidWhsOut = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
                createOverseaWhsOut(uuidWhsOut, createDate, userId, movementType, overseaRequisition);

                int i = 0;
                for (OverseaRequisitionDtl overseaRequisitionDtl : overseaRequisitionDtlList){
                    String actualMovementType = overseaRequisitionDtl.getActualMovementType();
                    double actualBasicUnit = overseaRequisitionDtl.getActualQtyBasicUnit();
                    if (movementType.equals(actualMovementType) && actualBasicUnit > 0){
                        Integer item = (i + 1) * 10;
                        createOverseaWhsOutDtl(uuidWhsOut, item, overseaRequisitionDtl, relateDocument);
                        i ++;
                    }
                }
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_CREATE.getDescZh(), OVERSEA_WHS_OUT_CREATE.getDescEn(), "");
            }

            updateOverseaRequisition(overseaRequisition, REQUISITION_DONE.getCode());
            iOverseaOperateLogService.addOverseaOperateLog(userId, overseaRequisition.getUuidRequisition(), REQUISITION_DONE.getDescZh(), REQUISITION_DONE.getDescEn(), "");

            QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>()
                    .eq("RELATE_DOCUMENT", relateDocument).orderByAsc("SPMS_ID");
            return ResponseResult.success()
                    .add("whsOutList", this.baseMapper.selectList(queryWrapper))
                    .add("overseaRequisition", iOverseaRequisitionService.getOverseaRequisition(uuidRequisition))
                    .add("overseaRequisitionDtlList", iOverseaRequisitionDtlService.getRequisitionDtlList(uuidRequisition));
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    ResponseResult checkGenerateOverseaWhsOut(OverseaWhsOutGenerateDTO overseaWhsOutGenerateDTO){
        if (overseaWhsOutGenerateDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String uuidRequisition = overseaWhsOutGenerateDTO.getUuidRequisition();
        String createDate = overseaWhsOutGenerateDTO.getCreateDate();
        Integer dataVersion = overseaWhsOutGenerateDTO.getDataVersion();
        if (StringUtils.isEmpty(uuidRequisition) || StringUtils.isEmpty(createDate) || INVALID_DATE.equals(createDate)){
            return ResponseResult.error("请求参数错误");
        }
        OverseaRequisition overseaRequisition = iOverseaRequisitionService.getOverseaRequisition(uuidRequisition);
        if (overseaRequisition == null){
            return ResponseResult.error("领用申请查询不存在");
        }
        if (!dataVersion.equals(overseaRequisition.getDataVersion())){
            return ResponseResult.error("数据已刷新请刷新后重试");
        }
        if (!overseaRequisition.getSpmsStatus().equals(REQUISITION_APPROVED.getCode())){
            return ResponseResult.error("领用申请当前状态禁止此操作");
        }
        List<OverseaRequisitionDtlDTO> overseaRequisitionDtlDTOList = overseaWhsOutGenerateDTO.getRequisitionDtlDTOList();
        if (overseaRequisitionDtlDTOList == null || overseaRequisitionDtlDTOList.size() == 0){
            return ResponseResult.error("请求参数明细行数据为空");
        }
        for (OverseaRequisitionDtlDTO dto : overseaRequisitionDtlDTOList){
            String actualMovementType = dto.getActualMovementType();
            if (StringUtils.isEmpty(actualMovementType)){
                return ResponseResult.error("领用申请明细行" + dto.getItem() + "实际移动类型为空");
            }
        }
        return ResponseResult.success();
    }

    int createOverseaWhsOut(String uuidWhsOut, String createDate, String userId, String movementType, OverseaRequisition overseaRequisition){
        OverseaWhsOut overseaWhsOut = new OverseaWhsOut();
        overseaWhsOut.setUuidWhsOut(uuidWhsOut);
        overseaWhsOut.setCreateDate(createDate);
        overseaWhsOut.setMovementType(movementType);
        overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_IN_DELIVERY.getCode());
        overseaWhsOut.setCreateUserid(userId);
        overseaWhsOut.setWerks(overseaRequisition.getWerks());
        overseaWhsOut.setWorkshopCode(overseaRequisition.getWorkshopCode());
        overseaWhsOut.setWhsLocationCode(overseaRequisition.getWhsLocationCode());
        overseaWhsOut.setRelateDocument(overseaRequisition.getSpmsId());
        overseaWhsOut.setCostCenter(overseaRequisition.getCostCenter());
        overseaWhsOut.setCostCenterName(overseaRequisition.getCostCenterName());
        overseaWhsOut.setComments(overseaRequisition.getComments());
        return this.baseMapper.insert(overseaWhsOut);
    }

    void createOverseaWhsOutDtl(String uuidWhsOut, Integer item, OverseaRequisitionDtl requisitionDtl, String relateDocument){
        OverseaWhsOutDtl whsOutDtl = new OverseaWhsOutDtl();
        whsOutDtl.setUuidWhsOut(uuidWhsOut);
        whsOutDtl.setItem(item);
        whsOutDtl.setWerks(requisitionDtl.getWerks());
        whsOutDtl.setWorkshopCode(requisitionDtl.getWorkshopCode());
        whsOutDtl.setWhsLocationCode(requisitionDtl.getWhsLocationCode());
        whsOutDtl.setMaterialNo(requisitionDtl.getMaterialNo());
        whsOutDtl.setIssueQtyBasicUnit(requisitionDtl.getActualQtyBasicUnit());
        whsOutDtl.setActualQtyBasicUnit(0.0);
        whsOutDtl.setBasicUnit(requisitionDtl.getBasicUnit());
        whsOutDtl.setIssueQtyUnitSales(requisitionDtl.getActualQtyUnitSales());
        whsOutDtl.setActualQtyUnitSales(0.0);
        whsOutDtl.setStorageInfo("[]");
        whsOutDtl.setUnitSales(requisitionDtl.getUnitSales());
        whsOutDtl.setMovementType(requisitionDtl.getActualMovementType());
        whsOutDtl.setRelateDocument(relateDocument);
        whsOutDtl.setRelateDocumentItem(String.valueOf(requisitionDtl.getItem()));
        iOverseaWhsOutDtlService.createOverseaWhsOutDtl(whsOutDtl);
    }

    int updateOverseaRequisition(OverseaRequisition overseaRequisition, String spmsStatus){
        overseaRequisition.setSpmsStatus(spmsStatus);
        return iOverseaRequisitionService.updateRequisition(overseaRequisition);
    }

    @Override
    public ResponseResult getWhsOutAndDtl(String uuidWhsOut) {
        if (StringUtils.isEmpty(uuidWhsOut)){
            return ResponseResult.error("请求参数错误");
        }
        return ResponseResult.success()
                .add("overseaWhsOut", this.baseMapper.selectOne(new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut)))
                .add("overseaWhsOutDtl", iOverseaWhsOutDtlService.getOverseaWhsOutDtlListMap(uuidWhsOut));
    }

    @Override
    public IPage getWhsOutPage(OverseaWhsOutQueryDTO overseaWhsOutQueryDTO) {
        IPage iPage = overseaWhsOutQueryDTO.getPage();
        List<Map<String, Object>> mapList = this.baseMapper.getWhsOutPage(iPage, overseaWhsOutQueryDTO);
        return iPage.setRecords(mapList);
    }

    /** 出库任务关闭：1-0； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult closeWhsOut(String uuidWhsOut, Integer dataVersion, String userId) {
        try {
            if (StringUtils.isEmpty(uuidWhsOut) || dataVersion == null){
                return ResponseResult.error("请求参数错误");
            }
            QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut);
            OverseaWhsOut overseaWhsOut = this.baseMapper.selectOne(queryWrapper);
            if (overseaWhsOut == null){
                return ResponseResult.error("请求出库任务不存在");
            }
            if (overseaWhsOut.getDataVersion().equals(dataVersion)){
                ResponseResult.error("数据已更新请刷新重试");
            }
            if (!OVERSEA_WHS_OUT_IN_DELIVERY.getCode().equals(overseaWhsOut.getSpmsStatus())){
                return ResponseResult.error("当前状态禁止此操作");
            }
            overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_DELETE.getCode());
            this.baseMapper.update(overseaWhsOut, queryWrapper);
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_DELETE.getDescZh(), OVERSEA_WHS_OUT_DELETE.getDescEn(), "");
            return ResponseResult.success("出库任务关闭");
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /** 更新出库任务及明细：1-1；1-2(扣库存)； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult updateWhsOut(OverseaWhsOutDTO overseaWhsOutDTO, String userId) {
        try {
            ResponseResult checkResult = checkUpdate(overseaWhsOutDTO);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            String uuidWhsOut = overseaWhsOutDTO.getUuidWhsOut();
            OverseaWhsOut overseaWhsOut = getOverWhsOut(uuidWhsOut);

            String spmsStatus = overseaWhsOutDTO.getSpmsStatus();
            String werks = overseaWhsOut.getWerks();
            String whsLocationCode = overseaWhsOut.getWhsLocationCode();

            /** 更新出库任务表头 */
            ResponseResult updateResult = updateOverseaWhsOut(overseaWhsOut, overseaWhsOutDTO);
            if (updateResult.getCode() != SUCCESS){
                log.info("=======RuntimeException=========\n" + updateResult.getMsg());
                throw new RuntimeException("出库任务表头更新失败：" + updateResult.getMsg());
            }

            /** 更新出库任务行项目 */
            ResponseResult updateDtlResult = updateOverseaWhsOutDtl(overseaWhsOutDTO);
            if (updateDtlResult.getCode() != SUCCESS){
                log.info("=======RuntimeException=========\n" + updateDtlResult.getMsg());
                throw new RuntimeException("出库任务明细更新失败：" + updateResult.getMsg());
            }

            /** 增加出库任务操作日志 */
            addOperateLog(uuidWhsOut, spmsStatus, userId);

            /** 目标状态为2，表示出库完成，更新储位库存；记录储位库存操作日志； */
            if (OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode().equals(spmsStatus)){
                ResponseResult updateInventoryResult = updateOverseaWhsOutInventory(uuidWhsOut, SUB, userId, OPERATION_TYPE3, werks, whsLocationCode, overseaWhsOut.getMovementType(), "领用出库");
                if (updateInventoryResult.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateInventoryResult.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateInventoryResult.getMsg());
                }
            }

            return getWhsOutAndDtl(uuidWhsOut);
        }catch (Exception e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    ResponseResult updateOverseaWhsOut(OverseaWhsOut overseaWhsOut, OverseaWhsOutDTO overseaWhsOutDTO){
        try {
            QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", overseaWhsOut.getUuidWhsOut());
            overseaWhsOut.setSpmsStatus(overseaWhsOutDTO.getSpmsStatus());
            overseaWhsOut.setRemarks(overseaWhsOutDTO.getRemarks());
            overseaWhsOut.setComments(overseaWhsOutDTO.getComments());
            this.baseMapper.update(overseaWhsOut, queryWrapper);
            return ResponseResult.success();
        }catch (Exception e){
            e.printStackTrace();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    ResponseResult updateOverseaWhsOutDtl(OverseaWhsOutDTO overseaWhsOutDTO){
        List<OverseaWhsOutDtlDTO> whsOutDtlDTOList = overseaWhsOutDTO.getWhsOutDtlDTOList();
        for (OverseaWhsOutDtlDTO whsOutDtlDTO : whsOutDtlDTOList){
            OverseaWhsOutDtl overseaWhsOutDtl = new OverseaWhsOutDtl();
            overseaWhsOutDtl.setUuidWhsOut(whsOutDtlDTO.getUuidWhsOut());
            overseaWhsOutDtl.setItem(whsOutDtlDTO.getItem());
            double actualQtyBasicUnit = whsOutDtlDTO.getActualQtyBasicUnit() == null ? 0.0 : whsOutDtlDTO.getActualQtyBasicUnit();
            double actualQtyUnitSales = whsOutDtlDTO.getActualQtyUnitSales() == null ? 0.0 : whsOutDtlDTO.getActualQtyUnitSales();
            overseaWhsOutDtl.setActualQtyBasicUnit(actualQtyBasicUnit);
            overseaWhsOutDtl.setActualQtyUnitSales(actualQtyUnitSales);
            overseaWhsOutDtl.setStorageInfo(whsOutDtlDTO.getStorageInfo() == null ? "[]" : whsOutDtlDTO.getStorageInfo());
            overseaWhsOutDtl.setRemarks(whsOutDtlDTO.getRemarks() == null ? "" : whsOutDtlDTO.getRemarks());
            int whsOutDtlUpdateResult = iOverseaWhsOutDtlService.updateWhsOutDtl(overseaWhsOutDtl);
            if (whsOutDtlUpdateResult < 1){
                return ResponseResult.error().add("error", "出库任务明细行更新错误");
            }
        }
        return ResponseResult.success();
    }
    
    ResponseResult updateOverseaWhsOutInventory(String uuidWhsOut, String operateType, String userId, String logType, String werks, String whsLocationCode, String movementType, String remark){
        List<OverseaWhsOutDtl> overseaWhsOutDtlList = iOverseaWhsOutDtlService.getOverseaWhsOutDtlList(uuidWhsOut);
        if (overseaWhsOutDtlList == null || overseaWhsOutDtlList.size() == 0){
            return ResponseResult.error("出库任务明细数据查询不存在");
        }
        for (OverseaWhsOutDtl overseaWhsOutDtl : overseaWhsOutDtlList){
            String materialNo = overseaWhsOutDtl.getMaterialNo();
            double actualQtyBasicUnit = overseaWhsOutDtl.getActualQtyBasicUnit();
            if (actualQtyBasicUnit > 0){
                //storageInfoArray 结构参考：[{"storageUuid":"f17e13b4d9ad4d39ba55548eff544391","qty":100,"storageNo":"C010101"}]
                JSONArray storageInfoArray = JSONArray.parseArray(overseaWhsOutDtl.getStorageInfo());
                for (int i = 0; i < storageInfoArray.size(); i ++){
                    JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                    String storageUuid = storageInfoObj.getString("storageUuid");
                    double qty = storageInfoObj.getDoubleValue("qty");
                    if (qty > 0){
                        ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, operateType);
                        if (updateInventory.getCode() != SUCCESS){
                            return updateInventory;
                        }
                        String comments = operateType.equals(ADD) ? WHS_OPERATE_LOG_ADD : WHS_OPERATE_LOG_SUB;
                        iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, logType, uuidWhsOut, comments, userId, remark, werks, whsLocationCode, movementType);
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    ResponseResult checkUpdate(OverseaWhsOutDTO overseaWhsOutDTO){
        if (overseaWhsOutDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String uuidWhsOut = overseaWhsOutDTO.getUuidWhsOut();
        String spmsStatus = overseaWhsOutDTO.getSpmsStatus();
        Integer dataVersion = overseaWhsOutDTO.getDataVersion();
        if (StringUtils.isEmpty(uuidWhsOut) || StringUtils.isEmpty(spmsStatus) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        if (!OVERSEA_WHS_OUT_IN_DELIVERY.getCode().equals(spmsStatus) && !OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求数据目标状态错误");
        }
        QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut);
        OverseaWhsOut overseaWhsOut = this.baseMapper.selectOne(queryWrapper);
        if (overseaWhsOut == null){
            return ResponseResult.error("请求出库任务不存在");
        }
        if (!overseaWhsOut.getDataVersion().equals(dataVersion)){
            return ResponseResult.error("数据已更新请刷新重试");
        }
        if (!OVERSEA_WHS_OUT_IN_DELIVERY.getCode().equals(overseaWhsOut.getSpmsStatus())){
            return ResponseResult.error("请求出库任务当前状态禁止此操作");
        }
        /** 目标状态为 2-出库完成，需要校验出库明细中实际操作 > 0 的行对应储位库存校验；库存不够则返回错误信息； */
        if (OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode().equals(spmsStatus)){
            List<OverseaWhsOutDtlDTO> whsOutDtlDTOList = overseaWhsOutDTO.getWhsOutDtlDTOList();
            if (whsOutDtlDTOList == null || whsOutDtlDTOList.size() == 0){
                return ResponseResult.error("出库任务明细行不能为空");
            }
            for (OverseaWhsOutDtlDTO whsOutDtl : whsOutDtlDTOList){
                String uuidWhsOutItem = whsOutDtl.getUuidWhsOut();
                Integer item = whsOutDtl.getItem();
                double actualQtyBasicUnit = whsOutDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    OverseaWhsOutDtl overseaWhsOutDtl = iOverseaWhsOutDtlService.getWhsOutDtl(uuidWhsOutItem, item);
                    if (overseaWhsOutDtl == null){
                        return ResponseResult.error("请求出库明细数据不存在");
                    }
                    String materialNo = overseaWhsOutDtl.getMaterialNo();
                    JSONArray storageInfoArray = JSONArray.parseArray(whsOutDtl.getStorageInfo());
                    if (storageInfoArray == null || storageInfoArray.size() == 0){
                        return ResponseResult.error("储位信息不正确");
                    }
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        String storageNo = storageInfoObj.getString("storageNo");
                        if (qty > 0){
                            WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                            if (whsStorageInventory == null){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                            }
                            if (qty > whsStorageInventory.getAvailableQty()){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                            }
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    /** 出库任务提交SAP：2-3；2-4；4-3；4-4；
     * 单据状态(0已删除;1出库中;2出库完成;3提交SAP成功;4提交SAP失败;5已撤销;)
     * */
    @Override
    public synchronized ResponseResult toSapWhsOut(String uuidWhsOut, Integer dataVersion, String postingDate, String userId) {
        ResponseResult checkResult = checkToSapWhsOut(uuidWhsOut, dataVersion, postingDate);
        if (checkResult.getCode() != SUCCESS){
            return checkResult;
        }
        QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut);
        OverseaWhsOut overseaWhsOut = this.baseMapper.selectOne(queryWrapper);

        Map<String, Object> dataHeadWhsOut = this.baseMapper.dataHeadWhsOut(uuidWhsOut, postingDate);
        List<Map<String, Object>> dataItemWhsOut = this.baseMapper.dataItemWhsOut(uuidWhsOut);
        if (dataItemWhsOut != null && dataItemWhsOut.size() > 0){
            JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(dataHeadWhsOut, dataItemWhsOut, "Z_SPMS_ANOMALY_POST", "ANOMALY_POST");
            log.info("=======海外领用出库请求SAP dataToSap=========\n" + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("=======海外领用出库请求SAP响应结果 message=========\n" + message);
            JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");

            if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))){
                String sapVoucherNumber = RETURN_DATA.getString("O_MBLNR").trim();
                String sapVoucherYear = RETURN_DATA.getString("O_MJAHR").trim();
                overseaWhsOut.setPostingDate(postingDate);
                overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_SAP_SUCCESS.getCode());
                overseaWhsOut.setSapVoucherNumber(sapVoucherNumber);
                overseaWhsOut.setSapVoucherYear(sapVoucherYear);
                this.baseMapper.update(overseaWhsOut, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_SAP_SUCCESS.getDescZh() + ":" + sapVoucherNumber,
                        OVERSEA_WHS_OUT_SAP_SUCCESS.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "出库任务提交SAP");

                return ResponseResult.success()
                        .add("overseaWhsOut", this.baseMapper.selectOne(queryWrapper))
                        .add("overseaWhsOutDtl", iOverseaWhsOutDtlService.getOverseaWhsOutDtlListMap(uuidWhsOut))
                        .add("sapReturnedMessage", message)
                        .add("dataToSap", dataToSap);
            } else {
                overseaWhsOut.setPostingDate(postingDate);
                overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_SAP_ERROR.getCode());
                this.baseMapper.update(overseaWhsOut, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_SAP_ERROR.getDescZh(),
                        OVERSEA_WHS_OUT_SAP_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "出库任务提交SAP");
                return ResponseResult.error()
                        .add("overseaWhsOut", this.baseMapper.selectOne(queryWrapper))
                        .add("sapReturnedMessage", message)
                        .add("dataToSap", dataToSap);
            }
        } else {
            return ResponseResult.error("没有可提交SAP的有效出库明细");
        }
    }

    ResponseResult checkToSapWhsOut(String uuidWhsOut, Integer dataVersion, String postingDate){
        if (StringUtils.isEmpty(uuidWhsOut) || StringUtils.isEmpty(postingDate) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaWhsOut overseaWhsOut = getOverWhsOut(uuidWhsOut);
        if (overseaWhsOut == null){
            return ResponseResult.error("请求出库任务不存在");
        }
        if (!dataVersion.equals(overseaWhsOut.getDataVersion())){
            return ResponseResult.error("数据已更新请刷新重试");
        }
        String spmsStatus = overseaWhsOut.getSpmsStatus();
        if (!spmsStatus.equals(OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode()) &&
                !spmsStatus.equals(OVERSEA_WHS_OUT_SAP_ERROR.getCode())){
            return ResponseResult.error("出库任务当前状态禁止此操作");
        }
        return ResponseResult.success();
    }


    /**
     单据状态(0已删除;1出库中;2出库完成;3提交SAP成功;4提交SAP失败;5已撤销;)
     出库任务撤销/退回操作：3-1(加库存)；2-1(加库存)；4-1(加库存)；
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult cancelWhsOut(String uuidWhsOut, Integer dataVersion, String cancelPostingDate, String userId) {
        try {
            ResponseResult checkResult = cancelCheck(uuidWhsOut, dataVersion, cancelPostingDate);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            OverseaWhsOut overseaWhsOut = getOverWhsOut(uuidWhsOut);
            String spmsStatus = overseaWhsOut.getSpmsStatus();
            String werks = overseaWhsOut.getWerks();
            String whsLocationCode = overseaWhsOut.getWhsLocationCode();
            QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut);
            if (spmsStatus.equals(OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode()) ||
                    spmsStatus.equals(OVERSEA_WHS_OUT_SAP_ERROR.getCode())){
                overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_IN_DELIVERY.getCode());
                this.baseMapper.update(overseaWhsOut, queryWrapper);

                addOperateLog(uuidWhsOut, OVERSEA_WHS_OUT_GO_BACK.getCode(), userId);

                ResponseResult updateInventoryResult = updateOverseaWhsOutInventory(uuidWhsOut, ADD, userId, OPERATION_TYPE2, werks, whsLocationCode, "", "领用出库撤销");
                if (updateInventoryResult.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateInventoryResult.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateInventoryResult.getMsg());
                }
                return getWhsOutAndDtl(uuidWhsOut);
            }
            if (spmsStatus.equals(OVERSEA_WHS_OUT_SAP_SUCCESS.getCode())){
                Map<String, Object> dataHead = this.baseMapper.dataHeadCancelWhsOut(uuidWhsOut, cancelPostingDate);
                JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(dataHead, null, "Z_SPMS_CANCEL", "SPMS_CANCEL");
                log.info("=======dataToSap=========\n" + dataToSap);
                JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                log.info("=======message=========\n" + message);
                JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))){
                    String cancelVoucherNumber = RETURN_DATA.getString("0_MBLNR");
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_CANCEL.getDescZh() + ":" + cancelVoucherNumber,
                            OVERSEA_WHS_OUT_CANCEL.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "出库任务撤销提交SAP");
                    overseaWhsOut.setSpmsStatus(OVERSEA_WHS_OUT_IN_DELIVERY.getCode());
                    overseaWhsOut.setCancelPostingDate(cancelPostingDate);
                    overseaWhsOut.setSapCancelVoucherNumber(cancelVoucherNumber);
                    this.baseMapper.update(overseaWhsOut, queryWrapper);

                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_IN_DELIVERY.getDescZh(),
                            OVERSEA_WHS_OUT_IN_DELIVERY.getDescEn(), "");

                    ResponseResult updateInventoryResult = updateOverseaWhsOutInventory(uuidWhsOut, ADD, userId, OPERATION_TYPE2, werks, whsLocationCode, "", "领用出库撤销");
                    if (updateInventoryResult.getCode() != SUCCESS){
                        log.info("=======RuntimeException=========\n" + updateInventoryResult.getMsg());
                        throw new RuntimeException("储位库存更新错误\n" + updateInventoryResult.getMsg());
                    }
                    return ResponseResult.success()
                            .add("overseaWhsOut", this.baseMapper.selectOne(queryWrapper))
                            .add("overseaWhsOutDtl", iOverseaWhsOutDtlService.getOverseaWhsOutDtlListMap(uuidWhsOut))
                            .add("sapReturnedMessage", message)
                            .add("dataToSap", dataToSap);
                } else {
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_CANCEL_ERROR.getDescZh(),
                            OVERSEA_WHS_OUT_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "出库任务撤销提交SAP");
                    return ResponseResult.error()
                            .add("overseaWhsOut", this.baseMapper.selectOne(queryWrapper))
                            .add("sapReturnedMessage", message)
                            .add("dataToSap", dataToSap);
                }
            }
            return ResponseResult.error("当前状态禁止此操作");
        } catch (FeignException feignException) {
            feignException.printStackTrace();
            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
        }
    }

    ResponseResult cancelCheck(String uuidWhsOut, Integer dataVersion, String cancelPostingDate){
        if (StringUtils.isEmpty(uuidWhsOut) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaWhsOut overseaWhsOut = getOverWhsOut(uuidWhsOut);
        if (overseaWhsOut == null){
            return ResponseResult.error("请求出库任务不存在");
        }
        if (!dataVersion.equals(overseaWhsOut.getDataVersion())){
            return ResponseResult.error("数据已更新请刷新重试");
        }
        String spmsStatus = overseaWhsOut.getSpmsStatus();
        if (!spmsStatus.equals(OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode()) &&
                !spmsStatus.equals(OVERSEA_WHS_OUT_SAP_SUCCESS.getCode()) &&
                !spmsStatus.equals(OVERSEA_WHS_OUT_SAP_ERROR.getCode())){
            return ResponseResult.error("出库任务当前状态禁止此操作");
        }
        if (spmsStatus.equals(OVERSEA_WHS_OUT_SAP_SUCCESS.getCode())){
            if (StringUtils.isEmpty(overseaWhsOut.getSapVoucherNumber()) || StringUtils.isEmpty(cancelPostingDate)
                    || INVALID_DATE.equals(cancelPostingDate)){
                return ResponseResult.error("请求参数错误");
            }
        }
        return ResponseResult.success();
    }

    OverseaWhsOut getOverWhsOut(String uuidWhsOut){
        if (StringUtils.isEmpty(uuidWhsOut)){
            return null;
        }
        QueryWrapper<OverseaWhsOut> queryWrapper = new QueryWrapper<OverseaWhsOut>().eq("UUID_WHS_OUT", uuidWhsOut);
        return this.baseMapper.selectOne(queryWrapper);
    }

    void addOperateLog(String uuidWhsOut, String targetStatus, String userId){
        if (targetStatus.equals(OVERSEA_WHS_OUT_IN_DELIVERY.getCode())){
            // 出库中
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_IN_DELIVERY.getDescZh(), OVERSEA_WHS_OUT_IN_DELIVERY.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getCode())){
            // 出库完成
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getDescZh(), OVERSEA_WHS_OUT_DELIVERY_COMPLETED.getDescEn(), "");
        }
        if (targetStatus.equals(OVERSEA_WHS_OUT_GO_BACK.getCode())){
            //退回修改
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuidWhsOut, OVERSEA_WHS_OUT_GO_BACK.getDescZh(), OVERSEA_WHS_OUT_GO_BACK.getDescEn(), "");
        }

    }
}
